#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void handler(int signo)
{
    std::cout << "child quite, father get a signo : " << signo << std::endl;
}
// 父进程可不可以对子进程进行回收，回收方法放在信号处理函数中呢
void ClearChild(int signo)
{
    // v1
    // if(signo == SIGCHLD)
    // {
    /*waitpid(-1, &wstatus, 0);
    The  waitpid()  system  call  suspends  execution of the calling thread until a child
    specified by pid argument has changed state.  By default, waitpid()  waits  only  for
    terminated children, but this behavior is modifiable via the options argument, as de‐
    scribed below.
    */
    //     pid_t rid = waitpid(-1, nullptr, 0);
    //     if(rid > 0)
    //     {
    //         std::cout << "wait child success: " << rid <<std::endl;
    //     }
    // }
    // std::cout << "wait sub process done" << std::endl;

    // v2  // 这个版本好像能完成任务，但是如果有50个退出了，另外50个还不退出呢 最后父进程还是得阻塞等待
    // if (signo == SIGCHLD)
    // {
    //     while (true)
    //     {
    //         pid_t rid = waitpid(-1, nullptr, 0);
    //         if (rid > 0)
    //         {
    //             std::cout << "wait child success: " << rid << std::endl;
    //         }
    //         else 
    //             break;
    //     }
    // }
    // std::cout << "wait sub process done" << std::endl;

    // v3
    // 不用处理，直接忽略，Linux系统可以实现自己回收
}

// 子进程的信号等待
int main()
{
    // signal(SIGCHLD, ClearChild);
    // 在Linux系统中，手动忽略子进程推出发的信号，就不用回收它，也不会产生僵尸进程
    // 其实在系统中，SIG_IGN信号本身就是 以忽略的方式来处理的
    // 为什么用户使用自定义处理信号的忽略方式，和系统自动忽略都是忽略，但用户传就会回收子进程，而进程的就不会呢
    // 因为在signal这里Liunx操作系统(只有Linux才有)做了特殊处理 所以我们在理解的时候就直接做一下区分，就是两个不同的处理方式
    signal(SIGCHLD, SIG_IGN);

    for (int i = 0; i < 100; i++)
    {
        pid_t id = fork();
        if (id == 0)
        {
            // child
            int cnt = 5;
            while (cnt--)
            {
                std::cout << "I am child process: " << getpid() << std::endl;
                sleep(1);
            }
            std::cout << "child process died" << std::endl;
            exit(0);
        }
    }
    // father
    while (true)
        sleep(1);
    return 0;
}

// void Print(sigset_t pending)
// {
//     std::cout << "curr process pending: " << std::endl;
//     for (int sig = 31; sig > 0; sig--)
//     {
//         if (sigismember(&pending, sig))
//             std::cout << "1";
//         else
//             std::cout << "0";
//     }
//     std::cout << "\n";
// }

// void handler(int signo)
// {
//     std::cout << "signo : " << signo << std::endl;
//     sigset_t pending;
//     sigemptyset(&pending);=
//     // 接收到指定信号后，处理信号会陷入死循环，即一直在处理该信号，
//     // 当再次接收到这个信号 就会自动屏蔽，直到这个信号处理完才会移除屏蔽
//     int count = 10;
//     while (count--)
//     {
//         sigpending(&pending);
//         Print(pending);
//         sleep(1);
//     }
// }

// int main()
// {
//     // 信号捕捉的另一种方法
//     // int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

//     /*
//     struct sigaction {
//         void     (*sa_handler)(int);                          // 自定义处理信号的方法
//         void     (*sa_sigaction)(int, siginfo_t *, void *);   // 一般不用
//         sigset_t   sa_mask;                                   // ？？？
//         int        sa_flags;                                  // 一般设置为0 即可
//         void     (*sa_restorer)(void);                        // 一般不用
//     };
//     */
//     std::cout << "pid : " << getpid() << "\n";
//     struct sigaction act, oact;
//     act.sa_handler = handler;
//     act.sa_flags = 0;
//     // sa_mask是用来，自定义要把哪些信号加入到本进程的信号屏蔽字中的
//     sigemptyset(&act.sa_mask);
//     sigaddset(&act.sa_mask, 3);
//     sigaddset(&act.sa_mask, 4);
//     sigaddset(&act.sa_mask, 5);

//     // 用sigaction来处理信号的原因：它正在处理一个信号时，就会屏蔽这个信号，当这个信号处理完了会把该信号移出屏蔽字中
//     sigaction(2, &act, &oact);

//     while (true)
//         sleep(1);
//     return 0;
// }
